iT邦幫忙

DAY 11
3

分享一些學習心得系列 第 11

LINQ自學筆記-打地基-物件和集合初始設定式

  • 分享至 

  • xImage
  •  

連續五篇委派相關的文章後,這篇來點輕鬆的,談談物件和集合初始設定式,以及超好用的自動實作屬性。
自學筆記這系列是我自己學習的一些心得分享,歡迎指教。這系列的分享,會以 C# + 我比較熟的 Net 3.5 環境為主。
另外本系列預計至少會切成【打地基】和【語法應用】兩大部分做分享。打地基的部分,講的是 LINQ 的組成元素,這部分幾乎和 LINQ 無關,反而是 C# 2.0、C# 3.0 的一堆語言特性,例如:型別推斷、擴充方法、泛型、委派等等,不過都會把分享的範圍限制在和 LINQ 應用有直接相關功能。
PS. LINQ 自學筆記幾乎所有範例,都可直接複製到 LINQPad 4 上執行(大多是用 Statements 和 Program 模式)。因為它輕巧好用,功能強大,寫範例很方便,請大家自行到以下網址下載最新的 LINQPad:http://www.LINQpad.net/。
在 C# 1.0/2.0 的版本,我們可以對 .Net 實值型別、字串和陣列做初始化設定:

int i = 99;
string s = "Leo";
string[] ary = new string[] {"Leo", "Alvin", "Rose"};

不過若類別包含多種不多型別的屬性,就無法透過這種方式處理,除非該類別有可接收多參數的建構子。但是這種方式對開發人員來說,屬性一多,很不方便,因為有時候建立執行個體只要初始化兩個屬性,有時候是三個,有時候是四個,而且還有可能同樣要初始化三個屬性,但是這次和下次要給預設值的是不同的屬性。若是用建構子帶預設值,那就要重複寫好多建構子,實在不直覺也不好用。這個問題,直到 C# 3.0 透過物件初始化設定式的語法才得以解決。

物件初始設定式(Object initializers)允許開發人員在建立物件執行個體的同時,對該物件的欄位、屬性指派初始值,而不需透過物件宣告時所定義之建構式。文字表達不是很清楚,看範例程式最易懂!先看在 C# 1.0/2.0 時,如果要給一個只有預設建構子(也就是無參數建構子)的自訂物件之執行個體指派欄位和屬性值,該怎麼做:

public class Person 
{ 
    private string name; 
    private string address; 
    private int age; 
    public string Name {get {return name;} set {name = value;}} 
    public string Address {get {return address;} set {address = value;}} 
    public int Age {get {return age;} set {age = value;}} 
}

void Main() 
{ 
    Person p = new Person(); 
    p.Name = "Leo"; 
    p.Address = "Taipei City, Taiwan(R.O.C)"; 
    p.Age = 35; 
}

在 C# 3.0 (也就是 VS2008,.Net 3.5 的版本)中,透過物件初始化設定式,上述建立 Person 執行個體的程式碼可以精簡如下:

void Main() 
{ 
    Person p = new Person() 
    { 
        Name = "Leo", 
        Address = "Taipei City, Taiwan(R.O.C)", 
        Age = 35 
    }; 
}

事實上,上述兩個寫法,編譯器編譯後的結果是相同的,所以這個語法精簡,其實是透過編譯器代為處理而已。這樣的好處除了精簡程式碼之外(請注意,對於宣告端的來說精簡的程度更高,因為省去寫好多不同參數的建構子),搭配集合初始化設定式,還有一個好處是可以讓複雜物件的初始化變成函數形態的寫法,方便撰寫程式也更容易理解:

public class Order 
{ 
    private int orderId; 
    private string customerName; 
    private List<Product> orderItems; 
    public string CustomerName {get {return customerName;} set {customerName = value;}} 
    public int OrderId {get {return orderId;} set {orderId = value;}} 
    public List<Product> OrderItems {get {return orderItems;} set {orderItems = value;}} 
}

public class Product 
{ 
    private int productId; 
    private string name; 
    public int ProductId {get {return productId;} set {productId = value;}} 
    public string Name {get {return name;} set {name = value;}} 
}

void Main() 
{ 
    Order o = new Order() 
    { 
        OrderId = 1314, 
        CustomerName = "Leo", 
        OrderItems = new List<Product> 
        { 
            new Product() 
            { 
                ProductId = 10, 
                Name = "Egg" 
            }, 
            new Product() 
            { 
                ProductId = 20, 
                Name = "Apple" 
            } 
        } 
    }; 
    o.Dump(); 
}

所謂「集合初始化設定式」(Collection initializers)指的就是上述程式碼中,我們新增 OrderItems 這個 List<Product> 的樣子。原本我們要新增一個物件到集合中,通常得利用 Add 的方法:

void Main() 
{ 
    Order o = new Order() 
    { 
        OrderId = 1314, 
        CustomerName = "Leo", 
        OrderItems = new List<Product>() 
    }; 
    Product p1 = new Product() 
    { 
        ProductId = 10, 
        Name = "Egg" 
    }; 
    Product p2 = new Product() 
    { 
        ProductId = 20, 
        Name = "Apple" 
    }; 
    o.OrderItems.Add(p1); 
    o.OrderItems.Add(p2); 
    o.Dump(); 
}

但透過集合初始化設定式,是不是看起來就清爽多了。

最後我們想要把上述的程式碼更精簡,也就是利用 C# 3.0 超級無敵好用的「自動實作屬性」(Auto-Implemented Properties)。它也是一個透過編譯器簡化我們撰寫程式碼的功能。簡化那個部分?就是不用再自行撰寫存放屬性值的私有欄位,編譯器會在編譯時期自動幫我們產生,這樣程式碼就可以大幅精簡,以上例訂單(Order)和產品(Product)類別來看,會變成這樣:

public class Order 
{ 
    public string CustomerName {get; set;} 
    public int OrderId {get; set;} 
    public List<Product> OrderItems {get; set;} 
}

public class Product 
{ 
    public int ProductId {get; set;} 
    public string Name {get; set;} 
} 

很棒對喔!自動實作屬性和 LINQ 構成元素無關,但是因為太好用了,所以一定要帶到,這樣後續文章要寫範例程式碼就可以輕鬆多了。
PS. 自動實作屬性,VB 要到 .Net 4.0 才提供。


上一篇
LINQ自學筆記-打地基-Lambda 運算式
下一篇
LINQ自學筆記-打地基-匿名型別
系列文
分享一些學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言